/*
 ------------------------------------------------------------------------------
 Copyright (C) 2013 Eternal Games.

 This file is part of the GLQuake source code.

 The GLQuake source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The GLQuake source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the GLQuake source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// client.h - client header
//


#ifndef __CLIENT_H__
#define __CLIENT_H__


#include "../common/common.h"
#include "../game/client/cg_public.h"
#include "../collision/cm_public.h"
#include "../renderer/r_public.h"
#include "../sound/s_public.h"
#include "../gui/gui_public.h"


/*
 ==============================================================================

 CONSOLE

 ==============================================================================
*/

// Prints text to the console.
// Handles cursor positioning, line wrapping, colored text, etc.
void			Con_Print (const char *text);

// Toggles the console on/off
void			Con_Toggle ();

// Forces the console off
void			Con_Close ();

// Handles key events
void			Con_KeyEvent (int key, bool down);

// Handles char events
void			Con_CharEvent (int c);

// Redraws the console, or notify lines if toggled off
void			Con_Redraw ();

// Initializes the console
void			Con_Init ();

// Shuts down the console
void			Con_Shutdown ();

/*
 ==============================================================================

 CINEMATICS

 ==============================================================================
*/

#define MAX_CINEMATICS					16

typedef int								cinHandle_t;

enum cinFlags_t {
	CIN_SYSTEM				= BIT(0),
	CIN_LOOPING				= BIT(1),
	CIN_SILENT				= BIT(2)
};

struct cinData_t {
	const byte *			image;
	bool					dirty;

	int						width;
	int						height;
};

// Plays a cinematic
cinHandle_t		CIN_PlayCinematic (const char *name, int flags);

// Runs a cinematic frame
cinData_t		CIN_UpdateCinematic (cinHandle_t handle, int time);

// Resets a cinematic
void			CIN_ResetCinematic (cinHandle_t handle, int time);

// Stops a cinematic
void			CIN_StopCinematic (cinHandle_t handle);

// Initializes the cinematic module
void			CIN_Init ();

// Shuts down the cinematic module
void			CIN_Shutdown ();

/*
 ==============================================================================

 KEYS

 ==============================================================================
*/

// These are the key numbers that should be passed to key event handlers.
// Normal keys should be passed as lowercased ASCII.
enum keyNum_t {
	K_TAB					= 9,
	K_ENTER					= 13,
	K_ESCAPE				= 27,
	K_SPACE					= 32,
	K_BACKSPACE				= 127,

	K_UPARROW,
	K_DOWNARROW,
	K_LEFTARROW,
	K_RIGHTARROW,

	K_INSERT,
	K_DELETE,
	K_HOME,
	K_END,
	K_PAGEUP,
	K_PAGEDOWN,

	K_LALT,
	K_RALT,
	K_LCTRL,
	K_RCTRL,
	K_LSHIFT,
	K_RSHIFT,

	K_LWIN,
	K_RWIN,
	K_MENU,

	K_F1,
	K_F2,
	K_F3,
	K_F4,
	K_F5,
	K_F6,
	K_F7,
	K_F8,
	K_F9,
	K_F10,
	K_F11,
	K_F12,

	K_PAUSE,
	K_CAPSLOCK,
	K_SCROLLLOCK,
	K_PRINTSCREEN,

	K_KP_HOME,
	K_KP_UPARROW,
	K_KP_PAGEUP,
	K_KP_LEFTARROW,
	K_KP_5,
	K_KP_RIGHTARROW,
	K_KP_END,
	K_KP_DOWNARROW,
	K_KP_PAGEDOWN,
	K_KP_INSERT,
	K_KP_DELETE,
	K_KP_SLASH,
	K_KP_STAR,
	K_KP_MINUS,
	K_KP_PLUS,
	K_KP_ENTER,
	K_KP_NUMLOCK,

	K_MOUSE1,
	K_MOUSE2,
	K_MOUSE3,
	K_MOUSE4,
	K_MOUSE5,
	K_MOUSE6,
	K_MOUSE7,
	K_MOUSE8,

	K_MWHEELUP,
	K_MWHEELDOWN,

	K_CTRL_POV1,
	K_CTRL_POV2,
	K_CTRL_POV3,
	K_CTRL_POV4,
	K_CTRL_POV5,
	K_CTRL_POV6,
	K_CTRL_POV7,
	K_CTRL_POV8,
	K_CTRL_POV9,
	K_CTRL_POV10,
	K_CTRL_POV11,
	K_CTRL_POV12,
	K_CTRL_POV13,
	K_CTRL_POV14,
	K_CTRL_POV15,
	K_CTRL_POV16,

	K_CTRL_BUTTON1,
	K_CTRL_BUTTON2,
	K_CTRL_BUTTON3,
	K_CTRL_BUTTON4,
	K_CTRL_BUTTON5,
	K_CTRL_BUTTON6,
	K_CTRL_BUTTON7,
	K_CTRL_BUTTON8,
	K_CTRL_BUTTON9,
	K_CTRL_BUTTON10,
	K_CTRL_BUTTON11,
	K_CTRL_BUTTON12,
	K_CTRL_BUTTON13,
	K_CTRL_BUTTON14,
	K_CTRL_BUTTON15,
	K_CTRL_BUTTON16,
	K_CTRL_BUTTON17,
	K_CTRL_BUTTON18,
	K_CTRL_BUTTON19,
	K_CTRL_BUTTON20,
	K_CTRL_BUTTON21,
	K_CTRL_BUTTON22,
	K_CTRL_BUTTON23,
	K_CTRL_BUTTON24,
	K_CTRL_BUTTON25,
	K_CTRL_BUTTON26,
	K_CTRL_BUTTON27,
	K_CTRL_BUTTON28,
	K_CTRL_BUTTON29,
	K_CTRL_BUTTON30,
	K_CTRL_BUTTON31,
	K_CTRL_BUTTON32,

	K_X360_DPAD_UP,
	K_X360_DPAD_DOWN,
	K_X360_DPAD_LEFT,
	K_X360_DPAD_RIGHT,
	K_X360_START,
	K_X360_BACK,
	K_X360_LEFT_THUMB,
	K_X360_RIGHT_THUMB,
	K_X360_LEFT_SHOULDER,
	K_X360_RIGHT_SHOULDER,
	K_X360_LEFT_TRIGGER,
	K_X360_RIGHT_TRIGGER,
	K_X360_A,
	K_X360_B,
	K_X360_X,
	K_X360_Y,

	MAX_KEYS				= 256
};

// In order from highest priority to lowest.
// If none of the catchers are active, bound key strings will be executed.
enum keyCatch_t {
	KEYCATCH_CONSOLE		= BIT(0),
	KEYCATCH_GUI			= BIT(1)
};

// Returns a key number to be used to index a key binding by looking at the
// given string. Single ASCII characters return themselves, while the K_* names
// are matched up.
int				Key_StringToKeyNum (const char *string);

// Returns a string (either a single ASCII char, or a K_* name) for the given
// key number
const char *	Key_KeyNumToString (int keyNum);

// Gets a key binding
const char *	Key_GetBinding (int keyNum);

// Sets a key binding
void			Key_SetBinding (int keyNum, const char *binding);

// Writes lines containing "bind <key> <command>" to the given file for all the
// active key bindings.
// Used for config files.
void			Key_WriteBindings (fileHandle_t f);

// Gets the current key catchers
int				Key_GetCatchers ();

// Adds the given key catchers
void			Key_AddCatchers (int catchers);

// Removes the given key catchers
void			Key_RemoveCatchers (int catchers);

// Returns true if the given key is down
bool			Key_IsDown (int key);

// Returns true if any key is down
bool			Key_IsAnyDown ();

// Returns true if any key is down
bool			Key_IsAnyDown ();

// Clears key states
void			Key_ClearStates ();

// Handles key events
void			Key_Event (int key, int time, bool down);

// Handles char events
void			Key_CharEvent (int c);

// Initializes key binding/input
void			Key_Init ();

// Shuts down key binding/input
void			Key_Shutdown ();

/*
 ==============================================================================

 INPUT

 ==============================================================================
*/

// If buttonBits_t is changed, this must be changed too!
enum keyButtonAction_t {
	KB_ATTACK,
	KB_USE,
	KB_SPRINT,
	KB_ZOOM,
	KB_4,
	KB_5,
	KB_6,
	KB_7,
	KB_8,
	KB_9,
	KB_10,
	KB_11,
	KB_12,
	KB_13,
	KB_14,
	KB_15,
	KB_16,
	KB_17,
	KB_18,
	KB_19,
	KB_20,
	KB_21,
	KB_22,
	KB_23,
	KB_24,
	KB_25,
	KB_26,
	KB_27,
	KB_28,
	KB_29,
	KB_30,
	KB_31,
	KB_MAX
};

struct keyButton_t {
	int						keys[2];			// Key nums holding it down

	int						downTime;			// Button down msec timestamp
	int						upTime;				// Button up msec timestamp

	bool					active;				// Current state
	bool					wasPressed;			// Set when down, not cleared when up

	bool					toggled;			// Toggled on/off on each down
};

extern keyButton_t			in_moveForward;
extern keyButton_t			in_moveBack;
extern keyButton_t			in_moveRight;
extern keyButton_t			in_moveLeft;
extern keyButton_t			in_moveUp;
extern keyButton_t			in_moveDown;
extern keyButton_t			in_turnRight;
extern keyButton_t			in_turnLeft;
extern keyButton_t			in_lookUp;
extern keyButton_t			in_lookDown;
extern keyButton_t			in_speed;
extern keyButton_t			in_strafe;
extern keyButton_t			in_voiceChat;
extern keyButton_t			in_buttons[KB_MAX];

// Processes a key button command
void			IN_KeyButtonDown (keyButton_t *kb, int key, int time);
void			IN_KeyButtonUp (keyButton_t *kb, int key, int time);

// Returns the fraction of the frame that the given key button was down
float			IN_KeyButtonState (keyButton_t *kb);

// Returns a key button for the given binding
keyButton_t *	IN_KeyButtonForBinding (const char *binding);

// Handles mouse movement events
void			IN_ClearMouseMoves (void);
void			IN_MouseMove (int samples, float *x, float *y);
void			IN_MouseMoveEvent (float x, float y);

// Handles controller axes events
void			IN_ClearControllerAxes (void);
float			IN_ControllerAxis (int axis, float deadZone, float saturation, float power, float scale);
void			IN_ControllerAxisEvent (int axis, float value);

// Clears mouse and controller device states
void			IN_ClearDeviceStates ();

// Polls mouse and controller devices and generates events
void			IN_PollDevices ();

// Activates mouse and controller devices
void			IN_ActivateDevices ();

// Deactivates mouse and controller devices
void			IN_DeactivateDevices ();

// Initializes mouse and controller devices
void			IN_InitDevices ();

// Shuts down mouse and controller devices
void			IN_ShutdownDevices ();

// Clears input states
void			IN_ClearStates ();

// This is called by the system when the main window gains or loses focus
void			IN_Activate (bool active);

// Initializes the input subsystem
void			IN_Init ();

// Shuts down the input subsystem
void			IN_Shutdown ();

/*
 ==============================================================================

 GLOBALS

 ==============================================================================
*/

#define MAX_MOUSE_SAMPLES				8
#define MAX_CONTROLLER_AXES				8

#define RESEND_TIMEOUT					3000

#define FPS_FRAMES						8

// Connection states
enum connectionState_t {
	CS_UNINITIALIZED,							// Only before initialization or for dedicated servers
	CS_DISCONNECTED,							// Not talking to a server
	CS_CONNECTING,								// Sending request packets to the server
	CS_CHALLENGING,								// Sending challenge packets to the server
	CS_CONNECTED,								// Connection established, getting game state
	CS_LOADING,									// Only during level load, never during main loop
	CS_PRIMED,									// Got game state, waiting for first frame
	CS_ACTIVE									// Game views should be displayed
};

struct packet_t {
	int						userCmdNumber;		// User command number when packet was sent
};

// The clientActive_t structure is wiped completely at every level change,
// potentially several times during an established connection
struct clientActive_t {
	int						time;
	int						oldTime;

	int						timeDelta;

	int						clientNum;

	// Snapshot information
	bool					snapshotAvailable;
	bool					snapshotExtrapolated;

	bool					snapshotValid;
	int						snapshotTime;
	int						snapshotSequence;

	// The client maintains its own idea of view angles, which are sent to the
	// server each frame.
	// It is cleared to zero upon entering each level.
	// The server sends a delta each frame which is added to the locally
	// tracked view angles to account for standing on rotating objects,
	// teleport direction changes, etc.
	glqAngles				viewAngles;

	// Stuff set by the game module
	glqAngles				jitterAngles;

	float					sensitivityScale;

	// Mouse movement
	int						mouseIndex;

	float					mouseX[MAX_MOUSE_SAMPLES];
	float					mouseY[MAX_MOUSE_SAMPLES];

	// Controller axes
	float					controllerAxis[MAX_CONTROLLER_AXES];

	// User commands
	userCmd_t				userCmds[USERCMD_BACKUP];
	int						userCmdNumber;

	// Information for local display
	int						stats[MAX_STATS];
	float					faceAnimationTime;
	float					itemGetTime[32];

	// Zooming
	bool					zoomed;
	int						zoomTime;

	// Packets information
	packet_t				packets[PACKET_BACKUP];

	// Server information
	int						serverId;
	char					serverMap[MAX_PATH_LENGTH];

	bool					serverPure;
};

// The clientConnection_t structure is wiped when disconnecting from a server,
// either to go to the main menu GUI or connect to a different server.
// A connection can be to either a server through the network layer or a demo
// through a file.
struct clientConnection_t {
	int						connectTime;		// For connection request retransmits
	int						connectCount;		// Number of times we requested a connection
	bool					connectRejected;	// If true, the server rejected our connection request

	netAdr_t				serverAddress;		// Address of server from original connect
	int						serverChallenge;	// From the server to use for connecting

	int						serverMessageSequence;
	int						serverCommandSequence;

	// Connection information
	netChan_t				netChan;

	int						lastSentTime;		// For retransmits
	int						lastReceivedTime;	// For time-outs

	int						timeOutCount;		// It requires several frames in a time-out condition to disconnect

	// Reliable commands to send to the server
	int						reliableCommandSequence;
	int						reliableCommandAcknowledge;
	char					reliableCommandList[MAX_RELIABLE_COMMANDS][MAX_STRING_LENGTH];

	// File download information
	fileHandle_t			downloadFile;		// Handle to download file

	// Demo recording/playback information
	bool					demoWaiting;		// Don't record until a non-delta compressed message is received
	bool					demoPlaying;
};

// The serverStatic_t structure is wiped only when the server is shutting down
struct clientStatic_t {
	connectionState_t		state;				// Connection status

	int						frameTime;
	int						frameMsec;

	bool					fullyInitialized;	// True if all the subsystems are initialized

	bool					playingCinematic;	// True if playing a cinematic

	int						fpsIndex;
	int						fpsTimes[FPS_FRAMES];

	// Active cinematic handle
	cinHandle_t				cinematicHandle;

	// Game module handle
	void *					gameLibHandle;

	// Local assets
	material_t *			whiteMaterial;
	material_t *			consoleMaterial;
	material_t *			consoleInputMaterial;
	material_t *			charsetMaterial;

	gui_t *					mainMenuGUI;

	// Connection information
	char					serverName[MAX_ADDRESS_LENGTH];
};

extern clientActive_t		cl;
extern clientConnection_t	clc;
extern clientStatic_t		cls;

extern cvar_t *				cl_timeNudge;
extern cvar_t *				cl_deltaCompress;
extern cvar_t *				cl_showTimeDelta;
extern cvar_t *				cl_showMessages;
extern cvar_t *				cl_showRate;
extern cvar_t *				cl_drawFPS;
extern cvar_t *				cl_voiceChat;
extern cvar_t *				cl_voiceChatMode;
extern cvar_t *				cl_maxPackets;
extern cvar_t *				cl_dupPackets;
extern cvar_t *				cl_nextCinematic;
extern cvar_t *				cl_timeOut;

extern cvar_t *				in_alwaysRun;
extern cvar_t *				in_toggleRun;
extern cvar_t *				in_toggleZoom;
extern cvar_t *				in_angleSpeedKey;
extern cvar_t *				in_pitchSpeed;
extern cvar_t *				in_yawSpeed;
extern cvar_t *				in_freeLook;
extern cvar_t *				in_forwardSpeed;
extern cvar_t *				in_sideSpeed;
extern cvar_t *				in_upSpeed;
extern cvar_t *				in_mouse;
extern cvar_t *				in_controller;

extern cvar_t *				m_showRate;
extern cvar_t *				m_smooth;
extern cvar_t *				m_sensitivity;
extern cvar_t *				m_accel;
extern cvar_t *				m_forward;
extern cvar_t *				m_side;
extern cvar_t *				m_pitch;
extern cvar_t *				m_yaw;

extern cvar_t *				c_deviceName;

void			CL_InitAll ();
void			CL_ShutdownAll ();

void			CL_NextCinematic ();

void			CL_Disconnect (bool restart);

void			CL_AddReliableCommand (const char *fmt, ...);

void			CL_RequestNextDownload ();
void			CL_RequestDownloads ();

void			CL_BuildUserCmd ();

void			CL_ReadPackets (bool dump);

void			CL_SendPacket ();
void			CL_SendCommands ();

void			CL_UpdateScreen ();

void			CL_ParseServerMessage (msg_t *msg);

void			CL_WriteDemoMessage ();

void			CL_RecordDemo_f ();
void			CL_StopRecording_f ();

void			CL_PlayDemo_f ();
void			CL_TimeDemo_f ();

/*
 ==============================================================================

 INTERFACE TO GAME MODULE

 ==============================================================================
*/

extern glqCGame_t *			glqCGame;

void			CG_RunFrame ();
void			CG_Redraw ();

void			CG_LoadLevel ();
void			CG_FreeLevel ();

void			CG_Init ();
void			CG_Shutdown ();


#endif	// __CLIENT_H__